#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>

int len=0;
char c[10];

void menu();
struct node
{
  int val;
  struct node * next;
};

struct node *top,*temp;

void print()
{
  temp=top;
  while(temp!=NULL)
  {
	 printf("%d\t",temp->val);
	 
	 temp=temp->next;
  }
  puts("");
}

void append(int val)
{
  struct node *rear;
  temp=(struct node *)malloc(sizeof(struct node *));
  temp->val=val;
  temp->next=NULL;
  rear=top;
  while(rear->next!=NULL)
	 rear=rear->next;
  rear->next=temp;
  //rear=temp;
  len++;
}
void sort()
{
  struct node *prev,*t;
  int i,j,val;
  temp=top;
  for(i=0;i<len-1;i++)   
  {
    temp=top;
    while(temp->next!=NULL)
    {
      if (temp->val>temp->next->val)
      {
	t=temp->next;
	temp->next=temp->next->next;
	if(temp!=top)
	  prev->next=t;
	else
	  top=t;
	t->next=temp;
	temp=t;
      }
      prev=temp;
      temp=temp->next;
    }
  }
  menu();
}

void reverse()
{
  struct node *new,*t;
  temp=top;
  new=NULL;
  while(temp!=NULL)
  {
	 t=new;
	 new=temp;
	 temp=temp->next;
	 new->next=t;
  }
  top=new;
  menu();
}

int index_element(int val)
{
  int ind=0;
  temp=top;
  while(temp!=NULL)
  {
	 if(temp->val==val)
		return ind;
	 ind++;
	 temp=temp->next;
  }
  return -1;
}

void insert_element(int ind,int val)
{
  struct node *t;
  int k=0;
  temp=top;
  while((temp!=NULL)&&(k<=len))
  {
    if(k==ind-1)
    {
      t=(struct node *)malloc(sizeof(struct node *));
      t->val=val;
      t->next=temp->next;
      temp->next=t;
      len++;
      menu();
    }
    if(ind==0)
    {
      t=(struct node *)malloc(sizeof(struct node *));
      t->val=val;
      t->next=top;
      top=t;
      len++;
      menu();
    }
    temp=temp->next;
    k++;
  }
  puts("INDEX NOT FOUND");
  menu();
}

void remove_element(int val)
{
  struct node *prev;
  temp=top;
  while(temp!=NULL)
  {
    if(val==temp->val)
    {
      if(temp==top)
      {
	top=temp->next;
	free(temp);
	len--;
	menu();
      }
      else
      {
	prev->next=temp->next;	  
	free(temp);
	len--;
	menu();
      }
    }
    else
    {
      prev=temp;
      temp= temp->next;
    }
  }
  printf("Element not found!!!\n");
  menu();
}

void delete_list()
{
  struct node *t;
  temp=top;
  while(temp!=NULL)
  {
	 top=top->next;
	 free(temp);
	 temp=top;
  }
  top=0;
}

int pop(int ind)
{
  int result=-1,k=0;;
  struct node *prev;
  temp=top;
  while(temp!=NULL)
  {
    if(k==ind)
    {
      result=temp->val;
      if(temp==top)
      {
	top=temp->next;
	free(temp);
	len--;
	return result;
      }
      else
      {
	prev->next=temp->next;	  
	free(temp);
	len--;
	return result;
      }
    }
    else
    {
      prev=temp;
      temp= temp->next;
      k++;
    }
  }
  puts("INDEX NOT FOUND");
  menu();
}

int count(int val)
{
  int count=0;
  temp=top;
  while(temp!=NULL)
  {
	 if(temp->val==val)
	 {
		count++;
	 }
	 temp=temp->next;
  }
  return count;
}


int search(int val)
{
  temp=top;
  while(temp!=NULL)
  {
	 if(temp->val==val)
		return 1;
	 temp=temp->next;
  }
  return 0;
}

void extend(int list[],int l)
{
  int i;
  for(i=0;i<l;i++)
  {
    append(list[i]);
  }
  menu();
}

void slicing(int sind,int eind,int mult)
{
  int i,j;
  temp=top;
  
  if((sind>len)||(sind<0)||(eind<sind)||(eind<0))
  {  
    puts("INVALID INDEX!!!");
    menu();
  }
  for(i=0;i<sind;i++)
    temp=temp->next;
  
  if(eind>len)
    eind=len;
  
  while((i<eind)&&(temp!=NULL))
  {
    printf("%d\t",temp->val);
    for(j=0;j<mult;j++)
    {
      temp=temp->next;
      if(temp==NULL)
      {
	puts("");
	return;
      }
    }
    i+=mult;
  }
}


void create(int val)
{
  top=(struct node *)malloc(sizeof(struct node *));
  top->val=val;
  top->next=NULL;
  len++;
}


void check_name(char str[],char ch)
{
  int i;
  if(strncmp(str,c,strlen(c))==0)
  {
    if(str[strlen(c)]==ch)
    {
      for(i=strlen(c)+1;i<strlen(str);i++)
      {
	str[i-strlen(c)-1]=str[i];
      }
      str[strlen(str)-strlen(c)-1]='\0';
    }
  }
  else
  {
    printf("ERROR!!!VARIABLE NAME NOT FOUND!!!\n");
    menu();
  }
  
}

int get_num(char s[],int pos)
{
  int num,j,k,spos;
  long val;    
  num=0;
  if(s[0]=='-')
    spos=1;
  else
    spos=0;
  for(j=spos;j<=pos;j++)
  {
    val=1;
    for(k=0;k<pos-j;k++)
    val=10*val;
    num+=((int)s[j]-48)*val;
  }	
   if(s[0]=='-')
    num=num*(-1);
  return num;
}
  
void get_list(int list[],char str[])
{
  char s[100];
  int i,num,l=0,pos;
  for(i=0;i<strlen(str);i++)
  {
    if((((int)str[i]<=57)&&((int)str[i]>=48))||(str[i]=='-'))
    {
      pos=-1;
      while((((int)str[i]<=57)&&((int)str[i]>=48))||(str[i]=='-'))
      {
	if((str[i]=='-')&&((int)str[i+1]<=57)&&((int)str[i+1]>=48))
	{
	  s[++pos]=str[i];
	  s[++pos]=str[i+1];
	  i+=2;
	}
	else
	  if((((int)str[i]<=57)&&((int)str[i]>=48)))
	  {
	    s[++pos]=str[i];
	    i++;
	  }
      }
      num=get_num(s,pos);
      list[l]=num;
      l++;
    }
  }
}

void find_val(char str[],int length)
{
  char s[10]="";
  int i=0,pos,j,list[length],l=0,num;
  while(str[i]!='=')
  {  
    c[i]=str[i];
    i++;
  }  
  c[i]='\0';
  check_name(str,'=');
  get_list(list,str);
  create(list[0]);
  for(i=1;i<length;i++)
    append(list[i]);
  menu();
}

int check_func_name(int li[],char str[],char s[])
{
  int i=0,no;
  if(strncmp(str,s,strlen(s))==0)
  {
    if(str[strlen(s)]=='(')
    {
      for(i=strlen(s)+1;i<strlen(str);i++)
        str[i-strlen(s)-1]=str[i];
      str[strlen(str)-strlen(s)-1]='\0';
      get_list(li,str);
      return 1;
    }
    else
      return 0;
  }
  else
    return 0;
}

void err_message()
{
  puts("COMMAND NOT FOUND!!!CHECK SPELLING");
  menu();
}

int check_len(char str[])
{
  int i,l=0,cnt=0;
  int j,k;
  char flag='t';
  for(i=0;i<strlen(str);i++)
  {
    if((str[i]=='[')||(str[i]=='('))
    {
      for(j=i+1;j<strlen(str);j++)
      {
	if((((int)str[j]>=48)&&((int)str[j]<=57))||(str[j]==']')||(str[j]==')'))
	{
	  flag='f';
	  break;
	}
	else
	  if(str[j]==',')
	    err_message();
      }
      if(flag=='f')
	break;
      else
	err_message();
    }
  }
	  
  for(i=0;i<strlen(str);i++)
  { 
    if(((int)str[i]>=48)&&((int)str[i]<=57))
    {
      for(k=i+1;k<strlen(str);k++)
      {
	if(str[k]==',')
	{
	  flag='t';
	  for(j=k+1;j<strlen(str);j++)
	  {
	    if(((int)str[j]>=48)&&((int)str[j]<=57))//||(str[j]==']')||(str[j]==')')||(str[j]==' '))
	      flag='f';
	    if(str[j]==',')
	    {
	      i=k;
	      break;
	    }
	  }
	  if(flag=='t')
	      err_message();
	  l++;
	  break;
	}
	else
	if((((int)str[k]>=48)&&((int)str[k]<=57))&&(str[k-1]==' '))
	  err_message();
      }
    }	
  }
  for(i=0;i<strlen(str);i++)
  {
    if((str[i]=='(')&&(str[i+1]==')'))
      return 0;
    if((str[i]=='[')&&(str[i+1]==']'))
      return 0;
    if(str[i]=='.')
      cnt++;
    
  }
    l++;
    if(cnt>1)
    {
      puts("COMMAND NOT FOUND!!!");
      menu();
    }
  return l;
} 

void check_errors(char str[],char ch1,char ch2,char ch3)
{
  char flag='t';
  int i,j,k,pos=-1,cnt1=0,cnt2=0,cnt3=0,cnt4=0;
 
  for(i=0;i<strlen(str);i++)
  {
    if(str[i]=='(')
      cnt1++;
    if(str[i]==')')
      cnt2++;
    if(str[i]=='[')
      cnt3++;
    if(str[i]==']')
      cnt4++;
    if((str[i]=='-')&&(!(((int)str[i+1]>=48)&&(int)str[i+1]<=57)))
      err_message();
    if((str[i+1]=='-')&&((((int)str[i]>=48)&&(int)str[i]<=57)))
      err_message();
  }
  
  if((cnt1!=cnt2)||(cnt3!=cnt4))
    err_message();
  
  if(ch3==':')
  {
    if((cnt1!=0)||(cnt3!=1))
      err_message();
  }
  
  if(cnt3>1)
    err_message();
  
	
  flag='t'; 	
  for(i=0;i<strlen(str);i++)
  {
    if(str[i]==ch1)
    {
      pos=i;
      break;
    }
  }
  if(pos==-1)
    err_message();
  
  for(i=pos;i<strlen(str);i++)
  {
    flag='t';
    if((((int)str[i]>=48)&&((int)str[i]<=57))||(str[i]=='(')||(str[i]==')')||(str[i]=='[')||(str[i]==']')||(str[i]==',')||(str[i]==' ')||(str[i]==ch3)||(str[i]=='-'))
    {
      flag='f';
      if(str[i]==ch1)
      {
	flag='t';
        for(j=i+1;j<strlen(str);j++)
        {
	  if(str[j]==ch1)
	    err_message();
	  else
	  if(str[j]==ch2)
	  {
	    for(k=j+1;k<strlen(str);k++)
	    {
	      if((str[k]!=')')&&(ch2==']'))
	        err_message();
	      if((ch2==')')&&(str[k]!=')'))
		err_message();
	    }
	    flag='f';
	  }
        }
      }
    }
    if(flag=='t')
      err_message();
  }
}

void other(char str[],int li[],int l)
{
  int cnt,i;
  check_name(str,'.');
  if((check_func_name(li,str,"append"))&&(l==1))
  {
    append(li[0]); 
    menu();
  }
  else
    if((check_func_name(li,str,"insert"))&&(l==2))
    {
      insert_element(li[0],li[1]);
    }
  else  
    if((check_func_name(li,str,"pop"))&&(l==1))
    {
      cnt=pop(li[0]);
      printf("%d\n",cnt);
      menu();
    }
  else  
    if((check_func_name(li,str,"reverse"))&&(l==0))
    {
      reverse(); 
    }
  else
    if((check_func_name(li,str,"count"))&&(l==1))
    {
      cnt=count(li[0]);
      printf("%d\n",cnt);
      menu();
    }
  else
    if((check_func_name(li,str,"remove"))&&(l==1))
    {
      remove_element(li[0]);
    }
  else
    if((check_func_name(li,str,"sort"))&&(l==0))
    {
      sort();
    }
  else
    if((check_func_name(li,str,"index"))&&(l==1))
    {
      cnt=index_element(li[0]);
      if(cnt==-1)
	printf("ELEMENT NOT FOUND!!!\n");
      else
        printf("%d\n",cnt);
      menu();
    }
  else
    if(check_func_name(li,str,"extend"))
    {
      extend(li,l); 
    }
  else
  {
    puts("ERROR!!!CHECK FUNCTION NAME OR NO. OF PARAMETERS");
    menu();
  }
  
}

void temp_func(char str[],int l)
{
  int li[l],a[1];
  if(l==0)
    other(str,a,l);
  else
    other(str,li,l);
}
	  
void menu()
{
  int i,l=0,li[1],j,cnt=0;
  char str[100]="",flag='t',f='t';
  printf(">>");
  gets(str);
  if(strcmp(str,"quit")==0)
  {
    delete_list();
    exit(EXIT_SUCCESS);
  }
  if(strcmp(str,"")==0)
    menu();
  if(strcmp(str,c)==0)
  {
    print();
    menu();
  }
  for(i=0;i<strlen(str);i++)
  {
    if(str[i]=='=')
    {
      f='f';
      check_errors(str,'[',']',' ');
      l=check_len(str);
      find_val(str,l);
    }   
    else
      if((str[i]=='i')&&(str[i+1]=='n'))
      {
	if(top == NULL)      
	{
	  printf("LIST NOT CREATED!!!\n");
	  menu();
	}
	for(j=0;j<strlen(c);j++)
	{
	  if(str[j+i+3]!=c[j])	    
	  {
	    flag='f';
	    puts("Variable NOT DECLARED!!!");
	    menu();
	    break;
	  }
	}
	if(flag=='t')
	{
	  f='f';
	  str[i-1]='\0';
	  get_list(li,str);
	  j=search(li[0]);
	  if(j==0)
	    printf("False\n");
	  else
	    printf("True\n");
	  menu();
	}
      }
    else
      if(str[i]=='.')
      {
	f='f';
	if(top == NULL)      
	{
	  printf("LIST NOT CREATED!!!\n");
	  menu();
	}
	check_errors(str,'(',')',' ');
        l=check_len(str);
	temp_func(str,l);
      }
    else
      if(str[i]==':')
      {
	f='f';
	if(top == NULL)      
	{
	  printf("LIST NOT CREATED!!!\n");
	  menu();
	}
	check_errors(str,'[',']',':');
	check_name(str,'[');
	cnt=0;
	for(j=0;j<strlen(str);j++)
	{
	  if(str[j]==':')
	  {
	    str[j]=',';
	    cnt++;
	    if(cnt>2)
	      err_message();
	  }  
	}
	get_list(li,str);
	if(cnt==2)
	  slicing(li[0],li[1],li[2]);
	else
	  slicing(li[0],li[1],1);
	puts("");
	menu();
      }

  } 
  if(f=='t')
  {
    printf("COMMAND NOT FOUND!!!\n");
    menu();
  }
}


void main()
{
  system("clear");
  puts("\t\tC IMPLEMENTATION OF PYTHON LISTS\n");
  puts("TYPE ALL COMMANDS AS WE USE THEM IN PYTHON");
  puts("e.g. to create list use a=[1,2,3] (a is any var name)");
  puts("to append use a.append(4)");
  puts("for extend use a.extend([3,4,5,6])");
  puts("for slicing use a[1:3:2]");
  puts("to print list type var name and press enter");
  puts("for searching use x in a");
  puts("OTHER FUNCTIONS :\npop ,remove, index, insert, count, reverse and sort\n");
  puts("\nNOTE: ONLY ONE VARIABLE CAN BE DECLARED.IF A NEW VARIABLE IS DECLARED THE OLDER ONE GETS FLUSHED\n");
  puts("TYPE quit to exit\n\n");
  menu();
}
